﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI.WebControls;
using System.Web.Services;
using Entidades.jSON;
using Entidades;
using Controladores;
using Web.Extensions;
using Web.Handlers;
using Web.Helpers;
using Newtonsoft.Json;
using Entidades.jSON.Sistema;
using Common;

namespace Web.Pages
{
    public partial class _Guion : BasePage
    {
        #region Private Members
        protected int _idProyecto;
        protected int _idGuion;
        #endregion

        #region Public Members
        public bool _registroInactivo = false;
        #endregion

        #region Events

        protected new void Page_Load(object sender, EventArgs e)
        {
            try
            {
                base.Page_Load(sender, e);

                if (!Page.IsPostBack)
                {
                    _idProyecto = Helpers.WebHelper.Pages.QueryString.GetParameter<Int32>(Common.WellKnownKeys.Page.Parameters.ID_PROYECTO);
                    _idGuion    = Helpers.WebHelper.Pages.QueryString.GetParameter<Int32>(Common.WellKnownKeys.Page.Parameters.ID_GUION);

                    this.CargarPagina(_idProyecto, WellKnownKeys.Entities.TiposProyecto.SERIE.Id, _idGuion);
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        protected void rptGuionItems_ItemDataBound(object sender, RepeaterItemEventArgs e)
        {

        }

        protected void rptGuionAutorizaciones_ItemDataBound(object sender, RepeaterItemEventArgs e)
        {

        }

        #endregion

        #region Private Methods

        private void CargarPagina(int idProyecto, int idTipoProyecto, int idGuion)
        {
            try
            {
                var tiposProyecto = TiposProyecto.ObtenerTodos();
                this.selGuion_TipoProyecto.Bind(tiposProyecto, "Id", "Texto");

                var proyectos = Proyectos.ObtenerTodos().Where(x => ((ProyectoInfo)(x.Valor)).IdTipo == idTipoProyecto).ToList();
                this.selGuion_Proyecto.Bind(proyectos, "Id", "Texto");

                var estados = EstadosGuion.ObtenerTodos();
                var estadosPosibles = new int[]
                {
                    WellKnownKeys.Entities.EstadosGuion.GENERADO.Id,
                    WellKnownKeys.Entities.EstadosGuion.EN_GRABACION.Id,
                    WellKnownKeys.Entities.EstadosGuion.FINALIZADO.Id
                };
                estados = estados.Where(x => estadosPosibles.Contains(x.Id)).ToList();
                this.selGuion_Estado.Bind(estados, "Id", "Texto");

                var usuariosActores = Usuarios.ObtenerTodos();
                    usuariosActores = usuariosActores.Where(x => ((UsuarioInfo)x.Valor).IdTipo == Common.WellKnownKeys.Entities.TiposUsuario.ACTOR.Id).ToList();
                this.selGuion_UsuarioActor.Bind(usuariosActores, "Id", "Texto");

                var tiposCancion = TiposCancion.ObtenerTodos();
                this.selGuion_TipoCancion.Bind(tiposCancion, "Id", "Texto");

                var usuariosInfo = Usuarios.ObtenerTodos();

                #region Direccion / Traduccion / Adaptacion / Mezcla / Temporizador

                var noActores = usuariosInfo.Where(x => (((UsuarioInfo) x.Valor).IdTipo != WellKnownKeys.Entities.TiposUsuario.ACTOR.Id));

                var directores_y_operadores = new int[] { Common.WellKnownKeys.Entities.TiposUsuario.DIRECTOR.Id, Common.WellKnownKeys.Entities.TiposUsuario.OPERADOR.Id };
                var freelances = new int[] { Common.WellKnownKeys.Entities.CategoriasUsuario.FREELANCE.Id };

                var users_directores_y_operadores = usuariosInfo.Where(x => directores_y_operadores.Contains(((UsuarioInfo)x.Valor).IdTipo));
                var users_directores_y_operadores_y_freelances = usuariosInfo.Where(x => directores_y_operadores.Contains(((UsuarioInfo)x.Valor).IdTipo) || freelances.Contains(((UsuarioInfo)x.Valor).IdCategoria));

                selGuion_Director.Bind(users_directores_y_operadores, "Id", "Texto");
                selGuion_Traductor.Bind(users_directores_y_operadores_y_freelances, "Id", "Texto");
                selGuion_Adaptador.Bind(users_directores_y_operadores_y_freelances, "Id", "Texto");
                selGuion_Mezclador.Bind(users_directores_y_operadores_y_freelances, "Id", "Texto");
                selGuion_Temporizador.Bind(noActores, "Id", "Texto");

                #endregion

                var estadosAutorizacion = new List<ListaInfo>
                {
                    new ListaInfo() {Id = 1, Texto = "Aprobada", Valor = 1},
                    new ListaInfo() {Id = 0, Texto = "Rechazada", Valor = 0}
                };
                this.selDialogAutorizaciones_Estado.Bind(estadosAutorizacion, "Id", "Texto");

                var guion = new ControladorBase<Guion>().ObtenerEntidad(idGuion);

                this.CargarGuion(guion);
                this.CargarCostos(guion, idTipoProyecto);
                this.CargarImportacion(guion);
                this.CargarAutorizaciones(guion);
            }
            catch (Exception)
            {
                throw;
            }   
        }

        private void CargarGuion(Guion guion)
        {
            try
            {
                if (guion == null)
                    return;

                var usuarioActual = SessionHelper.GetCurrentUser();
                if (usuarioActual == null)
                    return;

                //if (guion.Estado.Id == Common.WellKnownKeys.Entities.EstadosGuion.GENERADO.Id && usuarioActual.Tipo.Id != Common.WellKnownKeys.Entities.TiposUsuario.ADMINISTRADOR.Id)
                //    return;

                if (guion.Proyecto != null)
                {
                    this.selGuion_TipoProyecto.SetSelected(guion.Proyecto.Tipo.Id);

                    var proyectos = Proyectos.ObtenerTodos().Where(x => x.Habilitado && ((ProyectoInfo)(x.Valor)).IdTipo == guion.Proyecto.Tipo.Id).ToList();
                    this.selGuion_Proyecto.Bind(proyectos, "Id", "Texto");
                    this.selGuion_Proyecto.SetSelected(guion.Proyecto.Id);
                }

                if (guion.Estado != null)
                {
                    this.selGuion_Estado.SetSelected(guion.Estado.Id);

                    if ( TieneAutorizacionesPendientes(guion) )
                    {
                        var estados = new int[]
                        {
                            WellKnownKeys.Entities.EstadosGuion.EN_GRABACION.Id,
                            WellKnownKeys.Entities.EstadosGuion.FINALIZADO.Id
                        };
                        this.selGuion_Estado.RemoveItems(estados);
                    }
                }

                if ( guion.Director != null )
                    this.selGuion_Director.SetSelected(guion.Director.Id);

                if ( guion.Traductor != null )
                    this.selGuion_Traductor.SetSelected(guion.Traductor.Id);
                
                if ( guion.Adaptador != null )
                    this.selGuion_Adaptador.SetSelected(guion.Adaptador.Id);
                
                if ( guion.Mezclador != null )
                    this.selGuion_Mezclador.SetSelected(guion.Mezclador.Id);

                if ( guion.Temporizador != null )
                    this.selGuion_Temporizador.SetSelected(guion.Temporizador.Id);

                this.txtGuion_Titulo.Value      = guion.Titulo;
                this.txtGuion_Episodio.Value    = guion.Episodio > 0 ? guion.Episodio.ToString() : string.Empty;
                this.txtGuion_Duracion.Value    = guion.Duracion.ToString();
                this.txtGuion_Personajes.Value  = guion.Personajes.ToString();
                this.txtGuion_Paginas.Value     = guion.Paginas.ToString();
                this.txtGuion_Loops.Value       = guion.Loops.ToString();
                this.txtGuion_Comentarios.Value = guion.Comentarios ?? String.Empty;

                this._registroInactivo = !guion.Activo;
                
                #region Items

                this.rptGuionItems.DataSource = guion.Items;
                this.rptGuionItems.DataBind();

                #endregion

            }
            catch (Exception)
            {
                throw;
            }
        }

        private void CargarCostos(Guion guion, int idTipoProyecto)
        {
            GuionCosto costos = null;
            var gc = new GuionControlador();

            costos = guion != null
                ? gc.ObtenerCostoGuion(guion.Id)
                : gc.CopiarCostoMaestro(new ControladorBase<Costo>().ObtenerEntidad(x => x.TipoProyecto.Id == idTipoProyecto));

            if ( costos == null )
                costos = gc.CopiarCostoMaestro(new ControladorBase<Costo>().ObtenerEntidad(x => x.TipoProyecto.Id == idTipoProyecto));

            if ( costos != null )
            {
                this.txtGuion_Costos_Adaptacion.Value       = Common.Formatter.ToFixed(costos.Adaptacion);
                this.txtGuion_Costos_Cancion.Value          = Common.Formatter.ToFixed(costos.Cancion);
                this.txtGuion_Costos_Coro.Value             = Common.Formatter.ToFixed(costos.Coro);
                this.txtGuion_Costos_Direccion.Value        = Common.Formatter.ToFixed(costos.Direccion);
                this.txtGuion_Costos_LoopMinimo.Value       = Common.Formatter.ToFixed(costos.LoopMinimo);
                this.txtGuion_Costos_Loops.Value            = Common.Formatter.ToFixed(costos.Loops);
                this.txtGuion_Costos_Mezcla.Value           = Common.Formatter.ToFixed(costos.Mezcla);
                this.txtGuion_Costos_Palabras.Value         = Common.Formatter.ToFixed(costos.Palabras);
                this.txtGuion_Costos_Traduccion.Value       = Common.Formatter.ToFixed(costos.Traduccion);
                this.txtGuion_Costos_Temporizacion.Value    = Common.Formatter.ToFixed(costos.Temporizacion);
            }
        }

        private void CargarImportacion(Guion guion)
        {
            if (guion == null)
                return;

            var importacion = new ControladorBase<GuionImportacion>().ObtenerEntidad(x => x.Guion.Id == guion.Id);
            if ( importacion != null )
            {
                this.txtGuion_Importacion_Fecha.InnerHtml   = importacion.Fecha.ToDateAndTime();
                this.txtGuion_Importacion_Usuario.InnerHtml = importacion.Usuario.Descriptor;
                
                // TODO => try to avoid hardcoding !!!

                //this.txtGuion_Importacion_DOC.Value         = importacion.DOC;
                //this.txtGuion_Importacion_DOC.NavigateUrl   = Helpers.FileHelper.GetServerRoot() + Common.WellKnownKeys.Directories.Files.ScriptsUploaded + idGuion + "/" + importacion.DOC;
                this.txtGuion_Importacion_DOC.NavigateUrl   = String.Format( @"Handlers\DownloadFileHandler.ashx?downloadType={0}&idGuion={1}", (int)DownloadFileHandler.DownloadTypes.ScriptDoc, guion.Id );
                this.txtGuion_Importacion_DOC.Text          = importacion.DOC;
                this.txtGuion_Importacion_BRK.Value         = importacion.BRK;
                this.txtGuion_Importacion_STR.Value         = importacion.STR;
                //this.hdnGuion_Importacion_Directorio.Value  = Helpers.FileHelper.GetServerRoot() + Common.WellKnownKeys.Directories.Files.ScriptsUploaded + idGuion;
                this.hdnGuion_Importacion_Directorio.Value  = Common.WellKnownKeys.Directories.Files.ScriptsUploaded + guion.Id;
                this.lnkDescargarArchivos.HRef = String.Format( @"Handlers\DownloadFileHandler.ashx?downloadType={0}&idGuion={1}", (int)DownloadFileHandler.DownloadTypes.ScriptBundle, guion.Id );
            }
        }

        private void CargarAutorizaciones(Guion guion)
        {
            if (guion == null)
                return;

            this.rptGuionAutorizaciones.DataSource = guion.TransicionDeAutorizaciones;
            this.rptGuionAutorizaciones.DataBind();            
        }

        private static bool TieneAutorizacionesPendientes(Guion guion)
        {
            var tieneAutorizacionesPendientes = false;
            if (guion.TransicionDeAutorizaciones.Any())
            {
                var autorizacionCompleta =
                    guion.TransicionDeAutorizaciones.FirstOrDefault
                    (
                        x =>
                            x.Autorizacion.Id == WellKnownKeys.Entities.AutorizacionesGuion.PRODUCCION.Id &&
                            x.Aprobada == true
                    );

                if (autorizacionCompleta == null)
                    tieneAutorizacionesPendientes = true;
            }

            return tieneAutorizacionesPendientes;
        }

        #endregion

        #region Web Methods

        /// <summary>
        /// Guarda los datos de un Guión
        /// </summary>
        /// <param name="infoGuion"></param>
        /// <param name="infoGuionItems"></param>
        /// <param name="infoGuionCosto"></param>
        /// <returns></returns>
        [WebMethod]
        public static string guardarGuion(string infoGuion, string infoGuionItems, string infoGuionCosto)
        {
            var mensaje     = string.Empty;
            var resultado   = false;
            object valor    = null;
            try
            {
                var idEstadoGuionFinalizado = WellKnownKeys.Entities.EstadosGuion.FINALIZADO.Id;
                var idEstadoGuionAnterior = WellKnownKeys.Entities.DEFAULT_ID;

                var controladorGuion = new ControladorBase<Guion>();
                var controladorGuionEstado = new ControladorBase<GuionEstado>();
                var controladorProyecto = new ControladorBase<Proyecto>();
                var controladorUsuario = new ControladorBase<Usuario>();

                var guionInfo = JsonConvert.DeserializeObject<GuionInfo>(infoGuion);

                var guionCostoInfo = JsonConvert.DeserializeObject<GuionCostoInfo>(infoGuionCosto);

                var fechaActual = DateTime.Now;
                var usuarioActual = SessionHelper.GetCurrentUser();

                var usuario = controladorUsuario.ObtenerEntidad(usuarioActual.Id);

                #region Guion
                var guion = controladorGuion.ObtenerEntidad( guionInfo.Id );
                if ( guion == null )
                    guion = new Guion();
                else
                    idEstadoGuionAnterior = guion.Estado != null ? guion.Estado.Id : WellKnownKeys.Entities.DEFAULT_ID;

                guion.Adaptador     = controladorUsuario.ObtenerEntidad( guionInfo.IdAdaptador );
                guion.Director      = controladorUsuario.ObtenerEntidad( guionInfo.IdDirector );
                guion.Mezclador     = controladorUsuario.ObtenerEntidad( guionInfo.IdMezclador );
                guion.Traductor     = controladorUsuario.ObtenerEntidad( guionInfo.IdTraductor );
                guion.Temporizador  = controladorUsuario.ObtenerEntidad( guionInfo.IdTemporizador );
                guion.Estado        = controladorGuionEstado.ObtenerEntidad( guionInfo.IdEstado );
                guion.Proyecto      = controladorProyecto.ObtenerEntidad( guionInfo.IdProyecto );
                guion.Duracion      = guionInfo.Duracion;
                guion.Loops         = guionInfo.Loops;
                guion.Paginas       = guionInfo.Paginas;
                guion.Personajes    = guionInfo.Personajes;
                guion.Titulo        = guionInfo.Titulo;
                guion.Episodio      = guionInfo.Episodio;
                guion.Comentarios   = guionInfo.Comentarios;
                #endregion

                #region Items del Guion

                var itemNuevo = false;
                var guionInfoItems = JsonConvert.DeserializeObject<List<GuionItemInfo>>(infoGuionItems);

                if ( guion.Items == null )
                    guion.Items = new List<GuionItem>();

                #region Eliminar items
                //Eliminar los ítems actuales que no se encuentran en la nueva lista..
                var itemsEliminados = new List<int>();
                foreach(var item in guion.Items)
                {
                    var infoItem = guionInfoItems.FirstOrDefault(x => x.Id == item.Id);
                    var existe = guionInfoItems.Contains( infoItem );
                    if ( !existe )
                        itemsEliminados.Add( item.Id );
                }
                foreach(var id in itemsEliminados)
                {
                    var item = guion.Items.FirstOrDefault(x => x.Id == id);
                    guion.Items.Remove( item );
                }
                #endregion

                #region Agregar/Actualizar items
                foreach (var itemInfo in guionInfoItems)
                {
                    var guionItem = guion.Items.FirstOrDefault(x => x.Id == itemInfo.Id);
                    //if ( guionItem != null )
                    //    guionItem = new GuionControlador().ObtenerGuionItem(guionItem.Id);

                    itemNuevo = false;
                    if ( guionItem == null )
                    {
                        guionItem = new GuionItem();
                        itemNuevo = true;
                    }

                    guionItem.Subtitulado       = itemInfo.Subtitulado;
                    guionItem.Actor             = controladorUsuario.ObtenerEntidad(itemInfo.IdActor);
                    guionItem.FechaGrabacion    = itemInfo.FechaGrabacion.HasValue? itemInfo.FechaGrabacion.Value : new DateTime?();
                    guionItem.Guion             = guion;
                    guionItem.Loops             = itemInfo.Loops;
                    guionItem.Personaje         = itemInfo.Personaje;
                    guionItem.TipoCancion       = new ControladorBase<TipoCancion>().ObtenerEntidad(itemInfo.IdTipoCancion);

                    if ( itemNuevo )
                        guion.Items.Add( guionItem );
                }

                #endregion

                #endregion

                #region Costo del Guion
                if ( guion.Costo == null )
                    guion.Costo = new GuionCosto();

                guion.Costo.Adaptacion      = guionCostoInfo.Adaptacion;
                guion.Costo.Cancion         = guionCostoInfo.Cancion;
                guion.Costo.Coro            = guionCostoInfo.Coro;
                guion.Costo.Direccion       = guionCostoInfo.Direccion;
                guion.Costo.Guion           = guion;
                //guion.Costo.Id            = guionCostoInfo.Id;
                guion.Costo.LoopMinimo      = guionCostoInfo.LoopMinimo;
                guion.Costo.Loops           = guionCostoInfo.Loops;
                guion.Costo.Mezcla          = guionCostoInfo.Mezcla;
                guion.Costo.Palabras        = guionCostoInfo.Palabras;
                guion.Costo.Traduccion      = guionCostoInfo.Traduccion;
                guion.Costo.Temporizacion   = guionCostoInfo.Temporizacion;
                #endregion

                #region Auditoria Guion
                if ( guion.UsuarioCreacion.IsNull() )
                    guion.UsuarioCreacion       = usuario;
                if ( guion.FechaCreacion.IsNull() || guion.FechaCreacion == DateTime.MinValue )
                {
                    guion.FechaCreacion         = fechaActual;
                }
                guion.UsuarioUltimaModificacion = usuario;
                guion.FechaUltimaModificacion   = fechaActual;
                if ( guion.Estado.Id == idEstadoGuionFinalizado )
                {
                    guion.UsuarioTerminacion    = usuario;
                    guion.FechaTerminacion      = fechaActual;
                }
                #endregion

                #region Transición de Estados
                GuionControlador.AgregarTransicionDeEstado(guion, guionInfo.IdEstado, fechaActual, usuarioActual.Id);
                #endregion

                resultado = controladorGuion.GuardarEntidad( guion );
                if ( resultado )
                {
                    mensaje = "Los datos del Guión fueron guardados exitosamente.";
                    valor = new GuionInfo(guion);

                    ActualizarPagos(guion);

                    var guionFueFinalizado = (idEstadoGuionAnterior != idEstadoGuionFinalizado) && (guion.Estado.Id == idEstadoGuionFinalizado);
                    if (guionFueFinalizado)
                    {
                        EnviarMailNotificacionGuionFinalizado(guion);
                    }
                }
                else
                {
                    mensaje = "Hubo un error al intentar guardar los datos del Guión.";
                }
            }
            catch (Exception ex)
            {
                mensaje = "Hubo un error al intentar guardar los datos del Guión." + Environment.NewLine + ex.Message;
                LogError(ex);
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        /// <summary>
        /// Actualiza los datos de un Costo Maestro
        /// </summary>
        /// <param name="infoCostoMaestro"></param>
        /// <returns></returns>
        [WebMethod]
        public static string actualizarCostoMaestro(string infoCostoMaestro)
        {
            string mensaje  = string.Empty;
            bool resultado  = false;
            object valor    = null;
            try
            {
                var costoMaestroInfo = JsonConvert.DeserializeObject<CostoInfo>(infoCostoMaestro);
                var cb = new ControladorBase<Costo>();

                var costo = cb.ObtenerEntidad(x => x.TipoProyecto.Id == costoMaestroInfo.IdTipoProyecto);
                if (costo.IsNotNull())
                {
                    costo.Adaptacion    = costoMaestroInfo.Adaptacion;
                    costo.Cancion       = costoMaestroInfo.Cancion;
                    costo.Coro          = costoMaestroInfo.Coro;
                    costo.Direccion     = costoMaestroInfo.Direccion;
                    costo.LoopMinimo    = costoMaestroInfo.LoopMinimo;
                    costo.Loops         = costoMaestroInfo.Loops;
                    costo.Mezcla        = costoMaestroInfo.Mezcla;
                    costo.Palabras      = costoMaestroInfo.Palabras;
                    costo.Traduccion    = costoMaestroInfo.Traduccion;
                    costo.Temporizacion = costoMaestroInfo.Temporizacion;

                    resultado = cb.GuardarEntidad( costo );
                }
                if ( resultado )
                {
                    mensaje = "Los valores del Maestro de Costos fueron actualizados exitosamente.";
                    valor = new CostoInfo(costo);
                }
                else
                {
                    mensaje = "Hubo un error al intentar actualizar el Maestro de Costos.";
                }
            }
            catch (Exception ex)
            {
                //throw ex;
                mensaje = "Hubo un error al intentar actualizar el Maestro de Costos." + Environment.NewLine + ex.Message;
                LogError(ex);
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);        
        }

        /// <summary>
        /// Obtiene los datos de un Costo Maestro, según el Tipo de Proyecto
        /// </summary>
        /// <param name="idTipoProyecto"></param>
        /// <returns></returns>
        [WebMethod]
        public static string obtenerCostoMaestro(int idTipoProyecto)
        {
            var mensaje     = "Hubo un error al intentar actualizar el Maestro de Costos.";
            var resultado   = false;
            object valor    = null;
            try
            {
                var costo = new ControladorBase<Costo>().ObtenerEntidad(x => x.TipoProyecto.Id == idTipoProyecto);
                if ( costo.IsNotNull() )
                {
                    resultado   = true;
                    mensaje     = "Los Costos fueron obtenidos exitosamente.";
                    valor       = new CostoInfo(costo);
                }
            }
            catch (Exception ex)
            {
                //throw ex;
                mensaje = "Hubo un error al intentar obtener los Costos." + Environment.NewLine + ex.Message;
                LogError(ex);
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);        
        }

        /// <summary>
        /// Obtiene los Proyectos que corresponden a un Tipo de Proyecto dado
        /// </summary>
        /// <param name="idTipoProyecto"></param>
        /// <returns></returns>
        [WebMethod]
        public static string obtenerProyectos(int idTipoProyecto)
        {
            var mensaje     = string.Empty;
            var resultado   = false;
            object valor    = null;
            try
            {
                var proyectos = new ControladorBase<Proyecto>().ObtenerEntidades(x => x.Tipo.Id == idTipoProyecto);
                if (proyectos.IsNotNull())
                {
                    mensaje = "Proyectos obtenidos exitosamente.";
                    resultado = true;
                    //valor = proyectos.Select(proyecto => new ProyectoInfo(proyecto)).ToList();
                    valor = proyectos.Select(x => new ListaInfo() {Id = x.Id, Valor = x.Id, Texto = x.Nombre}).ToList();
                }
            }
            catch (Exception ex)
            {
                mensaje = "Hubo un error al intentar obtener los Proyectos para el Tipo de Proyecto seleccionado." + Environment.NewLine + ex.Message;
                LogError(ex);
            }
            return SessionHelper.BuildResponse(mensaje, resultado, valor);
        }

        #region Helpers
        private static void ActualizarPagos(Guion guion)
        {
            try
            {
                var controladorPagos = new ControladorBase<Pago>();
                var controladorReclamos = new ControladorBase<Reclamo>();

                var usuarios = new Dictionary<int, int>();

                var estadoPagoPendienteDePago = new ControladorBase<PagoEstado>().ObtenerEntidad(x => x.Id == WellKnownKeys.Entities.EstadosPago.PENDIENTE_DE_PAGO.Id);

                var idsPagosAEliminar = controladorPagos.ObtenerEntidades(x => x.Guion.Id == guion.Id).Select(x => x.Id).ToList();

                #region Tipos de Usuario
                if ( guion.Items.Count > 0 )
                    usuarios.Add( WellKnownKeys.Entities.TiposUsuario.ACTOR.Id, WellKnownKeys.Entities.DEFAULT_ID );
                if ( guion.Adaptador != null )
                    usuarios.Add(WellKnownKeys.Entities.TiposUsuario.ADAPTADOR.Id, guion.Adaptador.Id);
                if ( guion.Director != null )
                    usuarios.Add(WellKnownKeys.Entities.TiposUsuario.DIRECTOR.Id, guion.Director.Id);
                if ( guion.Mezclador != null )
                    usuarios.Add(WellKnownKeys.Entities.TiposUsuario.MEZCLADOR.Id, guion.Mezclador.Id);
                if ( guion.Traductor != null )
                    usuarios.Add(WellKnownKeys.Entities.TiposUsuario.TRADUCTOR.Id, guion.Traductor.Id);
                if ( guion.Temporizador != null )
                    usuarios.Add(WellKnownKeys.Entities.TiposUsuario.TEMPORIZADOR.Id, guion.Temporizador.Id);
                #endregion

                foreach (KeyValuePair<int, int> usuarioItem in usuarios)
                {                    
                    var idTipoUsuario       = usuarioItem.Key;
                    var idUsuario           = usuarioItem.Value;
                    var usuario             = default(Usuario);
                    var pago                = default(Pago);
                    switch (idTipoUsuario)
                    {
                        case WellKnownKeys.Entities.TiposUsuario.ACTOR.Id:
                            #region Cálculo del Pago
                            if ( guion.Items == null )
                                break;
                            var itemsPorActor = guion.Items.Where(x => x.Actor != null && x.FechaGrabacion.HasValue && x.Subtitulado == false).GroupBy(x => x.Actor.Id).ToList();
                            if ( itemsPorActor.IsNull() )
                                break;
                            foreach (var guionItems in itemsPorActor) //Items de Actores que participaron en el Guion, agrupados
                            {
                                var infoCalculoPagoActores = FacturacionHelper.CalcularPagoActores(guion.Proyecto.Tipo, guion.Costo, guionItems.ToList());
                                pago = CalcularPago(infoCalculoPagoActores, estadoPagoPendienteDePago, controladorPagos);
                                ActualizarListaPagosAEliminar(idsPagosAEliminar, pago);
                            }
                            #endregion
                            break;
                        case WellKnownKeys.Entities.TiposUsuario.ADAPTADOR.Id:
                        case WellKnownKeys.Entities.TiposUsuario.DIRECTOR.Id:
                        case WellKnownKeys.Entities.TiposUsuario.MEZCLADOR.Id:
                        case WellKnownKeys.Entities.TiposUsuario.TRADUCTOR.Id:
                            usuario = BasePage.GetUsuario( guion, idTipoUsuario );
                            if (usuario == null)
                                continue;
                            #region Cálculo del Pago
                            //if ( guion.Estado.Nombre.ToUpper() == WellKnownKeys.Entities.EstadosGuion.FINALIZADO )
                            //{
                                var infoCalculoPagoNoActores = FacturacionHelper.CalcularPagoNoActores(guion, idUsuario, idTipoUsuario, usuario.Categoria.Id);
                                pago = CalcularPago(infoCalculoPagoNoActores, estadoPagoPendienteDePago, controladorPagos);
                                ActualizarListaPagosAEliminar(idsPagosAEliminar, pago);
                            //}
                            #endregion
                            break;
                        case WellKnownKeys.Entities.TiposUsuario.TEMPORIZADOR.Id:
                            usuario = BasePage.GetUsuario( guion, idTipoUsuario );
                            if (usuario == null)
                                continue;
                            #region Cálculo del Pago
                            var infoCalculoPagoTemporizador = FacturacionHelper.CalcularPagoTemporizador(guion, idUsuario, idTipoUsuario, usuario.Categoria.Id);
                            pago = CalcularPago(infoCalculoPagoTemporizador, estadoPagoPendienteDePago, controladorPagos);
                            ActualizarListaPagosAEliminar(idsPagosAEliminar, pago);
                            #endregion
                            break;
                    }
                }

                // Eliminar Pagos obsoletos/desafectados
                foreach (var idPagoAEliminar in idsPagosAEliminar)
                {
                    // Si el Pago a eliminar tiene al menos 1 Reclamos asociado, entonces dar de baja al Pago, pero no eliminarlo..
                    var reclamos = controladorReclamos.ObtenerEntidades(x => x.Pago.Id == idPagoAEliminar);
                    if (reclamos != null && reclamos.Any())
                    {
                        var pago = controladorPagos.ObtenerEntidad(idPagoAEliminar);
                        if (pago != null)
                        {
                            pago.Activo = false;
                            pago.UsuarioUltimaModificacion = new ControladorBase<Usuario>().ObtenerEntidad(Helpers.SessionHelper.GetCurrentUser().Id);
                            pago.FechaUltimaModificacion = DateTime.Now;
                            controladorPagos.GuardarEntidad(pago);
                        }
                    }
                    else
                    {
                        // Si el Pago a eliminar no tiene ningún Reclamo asociado, directamente eliminarlo..
                        controladorPagos.EliminarEntidad(idPagoAEliminar);
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        private static void ActualizarListaPagosAEliminar(List<int> idsPagosAEliminar, Pago pago)
        {
            if (pago.IsNotNull())
            {
                idsPagosAEliminar.Remove(pago.Id);
            }            
        }

        private static Pago CalcularPago(FacturacionHelper.InfoCalculoPago infoCalculoPago, PagoEstado estadoPago, ControladorBase<Pago> controlador)
        {
            var pago = default(Pago);
            if (infoCalculoPago.IsNotNull())
            {
                pago = FacturacionHelper.GenerarPago(controlador, infoCalculoPago, estadoPago, null, null);
                if (pago.IsNotNull())
                {
                    pago.UsuarioUltimaModificacion = new ControladorBase<Usuario>().ObtenerEntidad( Helpers.SessionHelper.GetCurrentUser().Id );
                    pago.FechaUltimaModificacion = DateTime.Now;
                    controlador.GuardarEntidad(pago);
                }
            }
            return pago;
        }

        private static bool EnviarMailNotificacionGuionFinalizado(Guion guion)
        {
            var resultado = false;
            try
            {
                var programa = guion.Titulo + " - Episodio " + guion.Episodio;
                var director = guion.Director.Nombre + " " + guion.Director.Apellido;
                var asunto = string.Format("El Director {0} ha terminado el programa {1}.", director.ToUpper(), programa.ToUpper());
                var fecha = guion.FechaTerminacion.Value;
                var parametro = new ControladorBase<Parametro>().ObtenerEntidad();
                //var emailProveedores = parametro.EmailProveedores;
                //var destinatarios = MailHelper.CreateRecipientsList(emailProveedores, "Proveedores");
                var emailDirectores = parametro.EmailDirectores;
                var destinatarios = MailHelper.CreateRecipientsList(emailDirectores, "Directores");
                resultado = MailHelper.EnviarMailNotificacionGuionFinalizado(destinatarios, asunto, programa, fecha, director); 
            }
            catch (Exception)
            {
                throw;
            }
            return resultado;
        }

        #endregion

        #endregion
    }
}